/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com */

/*
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef TRI_EVENTS_H_
#define TRI_EVENTS_H_


#include "sigslot/sigslot.h"
#include "key_event.h"

namespace tri
{

/**
 * Specail key enums
 */
enum key {
	KEY_BACKSPACE = 8,
	KEY_ENTER = 13,
	KEY_ESC = 27,

	//non ascii keys
	KEY_LEFT = 100,
	KEY_UP,
	KEY_RIGHT,
	KEY_DOWN
};

class TEventsProcess;

class TAbstractEventComponent{
	
	friend class TEventsProcess;
	
public:
	TAbstractEventComponent();
	virtual ~TAbstractEventComponent();

	void requestFocus();
	int getEventState();
	bool isEnabled();
	void setEnabled(bool);
	bool hasFocus();
	void emit(int event,int key=0);
	void setTarget(std::string target);
	std::string getTarget();
	
	template<class desttype>
	inline void connect(int slot, desttype* object,void (desttype::*pmemfunc)(int)){
		sigslot::signal1<int, sigslot::multi_threaded_local>* r_Slot = getSlot1(slot);
		if (r_Slot!=NULL && object != NULL && pmemfunc != NULL){
			r_Slot->connect(object, pmemfunc);
		}
	}
	
	template<class desttype>
	inline void connect(int slot, desttype* object,void (desttype::*pmemfunc)()){
		sigslot::signal0<sigslot::multi_threaded_local>* r_Slot = getSlot0(slot);
		if (r_Slot!=NULL && object != NULL && pmemfunc != NULL){
			r_Slot->connect(object, pmemfunc);
		}
	}
	
	template<class desttype>
	inline void connect(int slot, desttype* object,void (desttype::*pmemfunc)(std::string)){
		sigslot::signal1<std::string,sigslot::multi_threaded_local>* r_Slot = getSlotWT1(slot);
		if (r_Slot!=NULL && object != NULL && pmemfunc != NULL){
			r_Slot->connect(object, pmemfunc);
		}
	}
	

protected:
	virtual sigslot::signal0<sigslot::multi_threaded_local>* getSlot0(int type);
	virtual sigslot::signal1<int,sigslot::multi_threaded_local>* getSlot1(int type);
	virtual sigslot::signal1<std::string,sigslot::multi_threaded_local>* getSlotWT1(int type);
	
	sigslot::signal0<sigslot::multi_threaded_local> BUTTON_CLICKED;
	sigslot::signal0<sigslot::multi_threaded_local> BUTTON_PRESSED;
	sigslot::signal0<sigslot::multi_threaded_local> BUTTON_RELEASED;
	sigslot::signal0<sigslot::multi_threaded_local> MOUSE_MOVE;
	sigslot::signal0<sigslot::multi_threaded_local> MOUSE_DRAG;
	sigslot::signal0<sigslot::multi_threaded_local> FOCUS_LOST;
	sigslot::signal0<sigslot::multi_threaded_local> FOCUS_RECEIVED;
	sigslot::signal0<sigslot::multi_threaded_local> MOUSE_ENTER;
	sigslot::signal0<sigslot::multi_threaded_local> MOUSE_EXIT;
	sigslot::signal0<sigslot::multi_threaded_local> VALUE_CHANGED;
	sigslot::signal0<sigslot::multi_threaded_local> UPDATED;
	
	sigslot::signal1<std::string,sigslot::multi_threaded_local> BUTTON_CLICKED_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> BUTTON_PRESSED_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> BUTTON_RELEASED_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> MOUSE_MOVE_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> MOUSE_DRAG_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> FOCUS_LOST_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> FOCUS_RECEIVED_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> MOUSE_ENTER_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> MOUSE_EXIT_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> VALUE_CHANGED_WT;
	sigslot::signal1<std::string,sigslot::multi_threaded_local> UPDATED_WT;

	sigslot::signal1<int,sigslot::multi_threaded_local> KEY_PRESSED;
	sigslot::signal1<int,sigslot::multi_threaded_local> KEY_RELEASED;
	sigslot::signal1<int,sigslot::multi_threaded_local> EVENT_STATE_CHANGE;

	void setEventState(int state);
	int m_MouseState;
	bool m_Enabled;
	std::string m_Target; 

};

class TEventsProcess {
	
	friend class TAbstractEventComponent;

public:
	static TEventsProcess* getSingleton();
	static void process_mouse_event(const TMouseEvent& m, TAbstractEventComponent* e);
	static void process_key_event(const TKeyEvent& m);
	static bool is_key_pressed(int button);
	static void requestFocus(TAbstractEventComponent*);
	bool assertPressedEntity(TAbstractEventComponent*);
	bool assertFocusEntity(TAbstractEventComponent*);
	bool assertMouseOverEntity(TAbstractEventComponent*);
	bool assertFocusRequestEntity(TAbstractEventComponent*);

private:
	TEventsProcess();
	virtual ~TEventsProcess();
	void _process_mouse_event(const TMouseEvent& m, TAbstractEventComponent* e);
	void _process_key_event(const TKeyEvent& m);
	
	TAbstractEventComponent* _pressed_entity;
	TAbstractEventComponent* _mouse_over_entity;
	TAbstractEventComponent* _focus_entity;
	TAbstractEventComponent* _focus_requested_entity;
	bool keys[256];

	static TEventsProcess* singleton;
};

TMouseEvent getMouseEvent();
	
}
#endif 
